package com.yyt2021.datasource.aspect;

import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.javassist.ClassClassPath;
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtMethod;
import org.apache.ibatis.javassist.NotFoundException;
import org.apache.ibatis.javassist.bytecode.CodeAttribute;
import org.apache.ibatis.javassist.bytecode.LocalVariableAttribute;
import org.apache.ibatis.javassist.bytecode.MethodInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.yyt2021.datasource.entity.DataSourceType;
import com.yyt2021.datasource.util.DynamicDataSourceContextHolder;
import com.yyt2021.util.StringUtils;

/**
 * 多数据源处理
 * 
 */
@Aspect
@Order(1)
@Component
public class DataSourceAspect {

	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Pointcut("@annotation(com.yyt2021.datasource.annotation.DataSource)" + "|| @within(com.yyt2021.datasource.annotation.DataSource)")
	public void dsPointCut() {

	}

	@Around("dsPointCut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

		// 方法执行前
		String classType = joinPoint.getTarget().getClass().getName();
		Class<?> clazz = Class.forName(classType);
		String clazzName = clazz.getName();
		String methodName = joinPoint.getSignature().getName(); // 获取方法名称
		Object[] args = joinPoint.getArgs();// 参数
		Map<String, Object> nameAndArgs = getFieldsName(this.getClass(), clazzName, methodName, args);// 获取被切参数名称及参数值
		System.out.println(nameAndArgs.toString());

		DataSourceType dataSourceType = getDataSource(nameAndArgs);
		if (StringUtils.isNotNull(dataSourceType)) {
			DynamicDataSourceContextHolder.setDataSourceType(dataSourceType.getDb());
		}

		try {
			// 去执行方法
			return joinPoint.proceed();
		} finally {
			// 销毁数据源 在执行方法之后
			DynamicDataSourceContextHolder.clearDataSourceType();
		}
	}

	private DataSourceType getDataSource(Map<String, Object> params) {
		String globalcode = (String) params.get("globalcode");
		return DataSourceType.getTypeByCode(globalcode);
	}

	/**
	 * -通过反射机制 获取被切参数名以及参数值
	 *
	 * @param cls
	 * @param clazzName
	 * @param methodName
	 * @param args
	 * @return
	 * @throws NotFoundException
	 */
	private Map<String, Object> getFieldsName(Class cls, String clazzName, String methodName, Object[] args)
			throws NotFoundException {
		Map<String, Object> map = new HashMap<String, Object>();

		ClassPool pool = ClassPool.getDefault();
		// ClassClassPath classPath = new ClassClassPath(this.getClass());
		ClassClassPath classPath = new ClassClassPath(cls);
		pool.insertClassPath(classPath);

		CtClass cc = pool.get(clazzName);
		CtMethod cm = cc.getDeclaredMethod(methodName);
		MethodInfo methodInfo = cm.getMethodInfo();
		CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
		LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
		if (attr == null) {
			// exception
		}
		// String[] paramNames = new String[cm.getParameterTypes().length];
		int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
		for (int i = 0; i < cm.getParameterTypes().length; i++) {
			map.put(attr.variableName(i + pos), args[i]);// paramNames即参数名
		}
		return map;
	}

}
